﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using BakalarskaPraca.Forms;
using BakalarskaPraca.Generation.Data;
using BakalarskaPraca.Generation.Tasks.Abstract;
using BakalarskaPraca.Interfaces;
using Microsoft.DirectX;

namespace BakalarskaPraca.Generation.Tasks
{
    public class GenerationOverview : GenerationProcess 
    {
        public struct PlantPoint
        {
            public Vector3 Position; 
            public int Humidity;
            public bool Available;
        }

        public float ScaleFactor;
        public PlantPoint[][] PlantPoints;

        //public GenerationOverview(ProgressViewer progressViewer, GenerationTarget[] targets) : base(progressViewer)
        
        public override void Run(IProgressReporter reporter)
        {
            float minX = this.Polygons.Min(t => t.Vertices.Min(v => v.Positions[0].X));
            float maxX = this.Polygons.Max(t => t.Vertices.Max(v => v.Positions[0].X));
            float minY = this.Polygons.Min(t => t.Vertices.Min(v => v.Positions[0].Y));
            float maxY = this.Polygons.Max(t => t.Vertices.Max(v => v.Positions[0].Y));

            int sizeX = (int)Math.Ceiling((maxX - minX) * this.ScaleFactor);
            int sizeY = (int)Math.Ceiling((maxY - minY) * this.ScaleFactor);
            this.PlantPoints = new PlantPoint[sizeX][];

            HumidityPolygon buffTarget = this.Polygons[0];
            for (int x = 0; x < sizeX; x++)
            {
                this.PlantPoints[x] = new PlantPoint[sizeY];
                for (int y = 0; y < sizeY; y++)
                {
                    PlantPoint p = new PlantPoint();
                    p.Position = new Vector3();
                    float realX = x / this.ScaleFactor + minX;
                    float realY = y / this.ScaleFactor + minY;
                    
                    if (buffTarget == null || buffTarget.GetHumidity(realX, realY) < 0)
                    {
                        if (this.Polygons.Any(t => t.GetHumidity(realX, realY) >= 0))
                        {
                            buffTarget = this.Polygons.First(t => t.GetHumidity(realX, realY) >= 0);
                        }
                        else
                        {
                            buffTarget = null;
                        }
                    }
                    if (buffTarget != null)
                    {
                        p.Position.X = realX;
                        p.Position.Y = realY;
                        p.Position.Z = buffTarget.GetZPoisiton(realX, realY);
                        p.Humidity = buffTarget.GetHumidity(realX, realY);
                        p.Available = true;
                    } 
                    this.PlantPoints[x][y] = p;
                }
                reporter.ReportProgress(x, sizeX);
            }
        }

        public GenerationOverview(List<HumidityPolygon> polygons, ModelData modelData) : base(polygons, modelData)
        {
            this.ScaleFactor = Properties.Settings.Default.PlantSimulationScaleFactor;
        }

        public unsafe Bitmap PreviewData()
        {
            int width = this.PlantPoints.Count();
            int height = this.PlantPoints[0].Count();

            Bitmap result = new Bitmap(width, height);

            BitmapData data = result.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly,
                                       result.PixelFormat);

            int pixelSize = 4;

            IntPtr dataHandle = data.Scan0;

            for (int y = 0; y < height; y++)
            {
                byte* dataRow = (byte*)dataHandle + (y * data.Stride);
                for (int x = 0; x < width; x++)
                {
                    dataRow[x * pixelSize] = (byte)(this.PlantPoints[x][y].Humidity);
                    dataRow[x * pixelSize + 1] = (byte)(this.PlantPoints[x][y].Available ? 0 : 255);
                    dataRow[x * pixelSize + 2] = (byte)(255 - this.PlantPoints[x][y].Humidity);
                    dataRow[x * pixelSize + 3] = 255;
                }
            }

            result.UnlockBits(data);

            return result;
        }
    }
}
